//
//  AccreteFileDownload.swift
//  ZLFileDemo_Example
//
//  Created by iOS on 2022/8/4.
//  Copyright © 2022 CocoaPods. All rights reserved.
//

import Foundation
import Alamofire

open class AccreteFileDownload: NSObject {
    
    public var progress: Progress? = nil
    public var success: Success? = nil
    public var fail: Fail? = nil
    
    public typealias Progress = (_ bytesRead:Int64,_ totalBytesRead:Int64,_ progrss:Double) -> Void
    public typealias Success = (_ reponse:Any) -> Void
    public typealias Fail = (_ error:Error?) -> Void
    
    public var accreteMaxCount: Int = 5
    public var accreteIndex: Int = 0
        
    @objc private var fromUrlStr: String = ""
    @objc public var toPath: String = ""
    
    private var cancelledData: Data? //用于停止下载时,保存已下载的部分
    private var downloadRequest: DownloadRequest? //下载请求对象
    private var destination: DownloadRequest.DownloadFileDestination? //下载文件的保存路径
    private var queue: DispatchQueue = DispatchQueue.global()
        
    @discardableResult
    /// 开始下载
    /// - Parameters:
    ///   - fromUrlStr: 下载的源地址
    ///   - toPath: 二进制需要写入的本地路径
    ///   - queue: 配置下载时的线程
    /// - Returns: 本类对象，方便链式调用
    public func download(from fromUrlStr: String, to toPath: String, queue:DispatchQueue? = DispatchQueue.global()) -> Self {
        if fromUrlStr != self.fromUrlStr {
            // 如果请求发生了变更，那就取消上次的下载任务，避免新的任务得不到响应
            cancelDownload()
        }
        self.queue = queue ?? .global()
        self.fromUrlStr = fromUrlStr
        self.toPath = toPath
        
        // 配置下载存储路径
        destination = {_,response in
            let saveUrl = URL(fileURLWithPath: toPath)
            return (saveUrl,[.removePreviousFile, .createIntermediateDirectories] )
        }
        
        // 这里直接就开始下载了
        startDownloadFile()
        
        return self
    }
    
    @discardableResult
    /// 链式接进度
    public func progress(_ handler: Progress? = nil) -> Self {
        self.progress = handler
        return self
    }
    
    @discardableResult
    /// 链式接成功事件
    public func success(_ handler: Success? = nil) -> Self {
        self.success = handler
        return self
    }
    
    @discardableResult
    /// 链式接失败事件
    public func fail(_ handler: Fail? = nil) -> Self {
        self.fail = handler
        return self
    }
    
    // 暂停下载
    public func suspendDownload() {
        if let task = downloadRequest?.task {
            task.suspend()
        }
    }
    
    // 继续下载
    public func resumeDownload() {
        if let task = downloadRequest?.task {
            task.resume()
        }
    }
    
    // 取消下载
    public func cancelDownload() {
        if let _ = downloadRequest?.task {
            downloadRequest?.cancel()
        }
        downloadRequest = nil
    }
    
    // 开始下载
    public func startDownloadFile() {
        if let cancelledData = cancelledData {
            cancelDownload()
            downloadRequest = Alamofire.download(resumingWith: cancelledData, to: destination)
            downloadRequest?.downloadProgress { (pro) in
                DispatchQueue.main.async {[weak self] in
                    self?.progress?(pro.completedUnitCount,pro.totalUnitCount,pro.fractionCompleted)
                }
            }
            downloadRequest?.responseData(queue: queue, completionHandler: downloadResponse)
        }else {
            // 先取消上次的记录
            cancelDownload()
            downloadRequest = Alamofire.download(fromUrlStr, headers: ["Accept": "image/*,*/*;q=0.8"], to: destination)
            downloadRequest?.downloadProgress { (pro) in
                DispatchQueue.main.async {[weak self] in
                    self?.progress?(pro.completedUnitCount,pro.totalUnitCount,pro.fractionCompleted)
                }
            }
            downloadRequest?.responseData(queue: queue, completionHandler: downloadResponse)
        }
    }
    
    //根据下载状态处理
    private func downloadResponse(response:DownloadResponse<Data>){
        switch response.result {
        case .success:
            if response.response?.statusCode != 200 {
                failure(response: response)
                return
            }
            accreteIndex = 0
            // 下载成功，比对长度是否达到
            let contentRange_Max = (response.response?.allHeaderFields["Content-Range"] as? String ?? "").ns.components(separatedBy: "/").last ?? ""
            let contentLength = response.response?.allHeaderFields["Content-Length"] as? String ?? ""
            let maxLength = Int(contentRange_Max != "" ? contentRange_Max : contentLength) ?? 0
            if let data = response.value, data.count >= maxLength {
                DispatchQueue.main.async {[weak self] in
                    self?.success?(response)
                }
                return
            }
            // 长度比对失败，就删除不完整的源文件
            try? FileManager.default.removeItem(atPath: toPath)
            DispatchQueue.main.async {[weak self] in
                self?.fail?(NSError(domain: "File corrupted, source removed.", code: 20001, userInfo: nil) as Error)
            }
        case .failure:
            failure(response: response)
        }
    }
    
    // 处理失败
    func failure(response: DownloadResponse<Data>) {
        // 意外停止的话,把已下载的数据存储起来
        cancelledData = response.resumeData
        
        let message = response.error?.localizedDescription ?? ""
        
        if message == "cancelled" {
            accreteIndex = 0
            return
        }
        
        // 尝试自动续载
        if accreteIndex < accreteMaxCount {
            accreteIndex += 1
            startDownloadFile()
            return
        }
        
        accreteIndex = 0
        DispatchQueue.main.async {[weak self] in
            self?.fail?(response.error)
        }
    }
    
}
